Problem s uvolnovanim pameti - chybove hlaseni - okno CPU

Otázka od: js-delphi@quick.cz

14. 4. 2004 4:35

Ahoj panove.
Mam dost velky problem. Aplikace, kterou jsem prevzal se chova velice
nestandardne a ja si s ni uz nevim rady.
Nektere "f-ce" (nemyslim function) se daji opakovat nekolikrat a pak zacnou
zpusobovat vyjimky. Pokud ladim kod primo v Delphi, tak mi to skace do pro me
nezvykleho okna CPU s hlasenim jako:
"Project ...\Project.exe raised too many consecutive exceptions: 'access violation at 0x0000000000 read of addres 0x0000000000'. Process Stopped. Use Step or Run to continue."
nebo
"... faulted with message: 'access violation at ...' ..."

Domnivam se tedy, ze ta aplikace a jeji knihovny spatne zachazeji s pameti -
souhlasite se mnou?
No a ted moje otazky.
(1) Stahl jsem si MemProof, ale vubec se v nem neorientuji. Nemohl byste me
nekdo navest co kde mam videt a co kdyz vidim, tak mi to rekne? (kdyz to bude
jak pro blbe, bude to nejlepsi   )
(2) muzete mi nekdo vysvetlit kdy a jak se uvolnuji ktere promenne, tridy,
objekty? Je treba rucne uvolnovat vsechno? Delam chybu, kdyz vsechno co
vytvarim (napr. L:=TStrings.Create;) pak uvolnuju vzdy pres FreeAndNil? Ja jsem
si vsiml ve zdrojovych kodech Delphi, ze to neni pouzivano tak casto jak bcyh
cekal a tak nevim, jestli postupuju spravne. Musim uvolnovat i stringy? Jak?
(3) MemProof mi hlasi chyby typu "Pokus o uvolneni neexistujiciho zdroje" -
muzete mi nekdo priblizit co asi tak delam/aplikace za chybu?

Predem vsem moc diky!
Jirka
--------------------------------------------------
Ing. Jiri Sokol; jiri.sokol@seznam.cz; 972 231 187
D6Prof+SP3; WinXPProf+SP1; FB 1.0.3
programator amater


Odpovedá: Petr Daricek

14. 4. 2004 6:53

> (1) Stahl jsem si MemProof, ale vubec se v nem neorientuji. Nemohl byste me
nekdo navest co kde mam videt a co kdyz vidim, tak mi to rekne? (kdyz to bude
jak pro blbe, bude to nejlepsi   )
> (2) muzete mi nekdo vysvetlit kdy a jak se uvolnuji ktere promenne, tridy,
objekty? Je treba rucne uvolnovat vsechno? Delam chybu, kdyz vsechno co
vytvarim (napr. L:=TStrings.Create;) pak uvolnuju vzdy pres FreeAndNil? Ja jsem
si vsiml ve zdrojovych kodech Delphi, ze to neni pouzivano tak casto jak bcyh
cekal a tak nevim, jestli postupuju spravne. Musim uvolnovat i stringy? Jak?
> (3) MemProof mi hlasi chyby typu "Pokus o uvolneni neexistujiciho zdroje" -
muzete mi nekdo priblizit co asi tak delam/aplikace za chybu?
>
> Predem vsem moc diky!
> Jirka

1) Koukni se na http://users.pandora.be/stefancr/Delphi%20-%20MemProof.htm
2) FreeandNil rozhodne neni chyba. Pri free se uvolni pamet, ale ukazatel stale
nekam ukazuje a tak neni poznat jestli neukazuje na platne data. Prirazenim
nilu se tohle osetri. Stringy uvolnovat nemusis. Uvolnuji se jen dynamicke
promenne a objekty(ty jsou take dynamicke). String nevytvaris pred pouzitim
pres zadny create ani new.

                             Petr Daricek


Odpovedá: Karel Rys

14. 4. 2004 7:14

js-delphi@quick.cz dne 14 Apr 2004 v 5:20:

> (3) MemProof mi hlasi chyby typu "Pokus o uvolneni
> neexistujiciho zdroje" -
 muzete mi nekdo priblizit co asi tak
> delam/aplikace za chybu?

To je prave problem - znamena to, ze se napr. udelalo Objekt.Free a potom se
nekde znovu vola
Objekt.Free - pokousi se to uvolnit podruhe. Nebo se vola FreeMem a preda se
promenna, do ktere se
predtim pamet nealokovala...

Karel Rys


Odpovedá: js-delphi@quick.cz

14. 4. 2004 8:13

Odesilatel: Karel Rys <delphi@zas-me.cz>
> > (3) MemProof mi hlasi chyby typu
"Pokus o uvolneni
> > neexistujiciho zdroje" - muzete mi nekdo priblizit co
asi tak
> > delam/aplikace za chybu?
>
> To je prave problem - znamena to, ze se napr. udelalo Objekt.Free
> a potom se nekde znovu vola
> Objekt.Free - pokousi se to uvolnit podruhe. Nebo se vola FreeMem
> a preda se promenna, do ktere se
> predtim pamet nealokovala...

No a jak se to spravne otestuje? Kdy mam pouzit:
if Asssigned(L) then FreeAndNil(L);
a kdy
if L <> nil then FreeAndNil(L);
Je teda spravne, ze jsem temer vsude misto "L.free" nasekal FreeAndNil(L). Pak
mi neni jasne, proc to zlobi cim dal vic...

Jeste jeden dotaz:
Jak spravne uvolnim takovouhle pamet?
procedure Neco;
var
 L:TStringList;
begin
  ...
  L:=Funkce01;
end;

function Funkce01;
begin
  result:=TStringList.Create;
  result.add('a');
  result.add('b');
  result.add('c');
end;

Z niceho nic mi aplikace zacala padat na jakykoliv pokus o uvolneni pameti -
vsechno konci s chybou (FreeAndNil(L), L.Free) JAK TO??? Testoval jsem to pred
tim uvolnenim:
if L <> nil then FreeAndNil(L);
ale to stejne konci vyjimkou...

Diky za Vase rady. Ocenim jakekoliv Vase zkusenosti - zkuste mi napsat jake
jste delali chyby ve svych zacatcich - treba se jich taky dopoustim a jeste to
ani neumim spravne popsat!

Jirka
--------------------------------------------------
Ing. Jiri Sokol; jiri.sokol@seznam.cz; 972 231 187
D6Prof+SP3; WinXPProf+SP1; FB 1.0.3
programator amater


Odpovedá: Karel Rys

14. 4. 2004 8:50

js-delphi@quick.cz dne 14 Apr 2004 v 9:02:

> No a jak se to spravne otestuje? Kdy mam pouzit:
> if Asssigned(L) then FreeAndNil(L);
> a kdy
> if L <> nil then FreeAndNil(L);
> Je teda spravne, ze jsem temer vsude misto "L.free" nasekal
> FreeAndNil(L). Pak mi neni jasne, proc to zlobi cim dal vic...

Rekl bych, ze FreeAndNil si to testuje samo - pokud je predavany objekt nil,
neudela nic; pokud
neni nil, uvolni ho volanim objekt.Free a nastavi ho na nil (takze se pri
pristim volani
FreeAndNil uz nestane nic).

> Jeste jeden dotaz:
> Jak spravne uvolnim takovouhle pamet?
> procedure Neco;
> var
> L:TStringList;
> begin
> ...
> L:=Funkce01;
> end;
>
> function Funkce01;
> begin
> result:=TStringList.Create;
> result.add('a');
> result.add('b');
> result.add('c');
> end;

Spis bych zvazil, zda pouzivat takovyhle zpusob vytvareni objektu. Napsal bych
to radeji nejak
takto:

procedure Neco;
var
 L:TStringList;
begin
 L:=tStringList.Create;
 try
  Fuknce01(L);
  ...
 finally
  FreeAndNil(L); // nebo L.Free;
 end;
end;

procedure Funkce01(Cil:tStringList);
begin
  Cil.add('a');
  Cil.add('b');
  Cil.add('c');
end;

> Diky za Vase rady. Ocenim jakekoliv Vase zkusenosti - zkuste mi napsat
> jake jste delali chyby ve svych zacatcich - treba se jich taky
> dopoustim a jeste to ani neumim spravne popsat!

Rekl bych, ze chybam se da slusne predchazet v pripade, ze alokaci i uvolneni
muzes dat do jedne
casti kodu, tj. klasicke:

L:=tNeco.Create;
try
 .....
finally
 L.Free; // nebo FreeAndNil
end;


Karel Rys


Odpovedá: Petr Fejfar

14. 4. 2004 9:13

js-delphi@quick.cz wrote:

> Diky za Vase rady. Ocenim jakekoliv Vase zkusenosti - zkuste mi
> napsat jake jste delali chyby ve svych zacatcich - treba se jich taky
> dopoustim a jeste to ani neumim spravne popsat!

Za meho mladi jsme takove chyby proste nedelali,
protoze nez nas nekdo pustil k pocitaci, tak jsme
museli nastudovat radu script a manualu
- byli jsme tudiz teoreticky slusne pripraveni <g>

Vazne - chce to teoretickou prupravu - pokud si nebudes
na Tebou kladene otazky schopen odpovedet sam,
tak se IMHO s tim memory managementem nikdy
nevyporadas a vysledkem bude jen nejaky vice ci mene
nahodily slepenec a ne aplikace, nad kterou mas kontrolu.

Alespon si precti v helpu kapitoly

    - Object Pascal Reference | Memory management
    - Object Pascal Reference | Program control

a taky si projdi popis metod basalni tridy TObject - doporucuji spojit
s nahlizenim do zdrojovek RTL dodavanych s Delphi.


HTH, pf

Odpovedá: jsdelphi@creatix.cz

14. 4. 2004 11:39

>Jak spravne uvolnim takovouhle pamet?
>procedure Neco;
>var
>L:TStringList;
>begin
> ...
> L:=Funkce01;
>end;

>function Funkce01;
>begin
> result:=TStringList.Create;
> result.add('a');
> result.add('b');
> result.add('c');
>end;

Ja bych pouzil konstrukci:

procedure Neco;
var
  L: TStringList;
begin
  ...
  L := Funkce01;
  try
  ...
  finally
    FreeAndNil(L);
  end;
end;

function Funkce01;
begin
  result := TStringList.Create;
  result.add('a');
  result.add('b');
  result.add('c');
end;

Jan Skopovy


Odpovedá: Petr Vones

14. 4. 2004 12:20

From: <js-delphi@quick.cz>
> Je teda spravne, ze jsem temer vsude misto "L.free" nasekal FreeAndNil(L).

Neni. Je treba nejdrive pochopit jak vubec sprava pameti funguje. Pak nebudes
(ve vetsine pripadu   delat chyby ktere povedou k takovym problemum. Anebo
prejdi na .NET kde tyto problemy z principu neexistuji, ale zase jsou tam
jine.

> function Funkce01;
> begin
> result:=TStringList.Create;
> result.add('a');
> result.add('b');
> result.add('c');
> end;

Jestlize funkce vraci jako result nejaky objekt tak by to melo obecne vypadat
spise takto, protoze v pripade ze dojde k vyjimce pri volani nekterych metod
toho objektu je nutne objekt v dane funkci explicitne uvolnit pred vyvolanim
vyjimky:

function Funkce01: TStringList;
begin
  Result := TStringList.Create;
  try
    // zde muze dojit k nejake vyjimce
    Result.Add('a');
    Result.Add('b');
    Result.Add('c');
  except
    Result.Free;
    raise;
  end;
end;

Samozrejme zalezi na navrhu, objekt se muze v konstruktoru sam pridat do
nejakeho seznamu ktery jej pozdeji uvolni apod. Jako dalsi reseni se nabizi
pouzit interface, pak se o uvolnovani nemusis starat, ale ma to zase jine
nevyhody.

Petr Vones


Odpovedá: Martin Schayna

14. 4. 2004 15:33

Petr Fejfar <development@callnet.cz> wrote:
> js-delphi@quick.cz wrote:
>> Diky za Vase rady. Ocenim jakekoliv Vase zkusenosti - zkuste mi
>> napsat jake jste delali chyby ve svych zacatcich - treba se jich taky
>> dopoustim a jeste to ani neumim spravne popsat!
>
> Za meho mladi jsme takove chyby proste nedelali,
> protoze nez nas nekdo pustil k pocitaci, tak jsme
> museli nastudovat radu script a manualu
> - byli jsme tudiz teoreticky slusne pripraveni <g>

<G>. Mas naprostou pravdu. I kdyz tenkrat jsme se
to ucili s "opravdovymi" pointery a rucnim alokovanim
pameti GetMem/FreeMem resp. New/Dispose, coz
je zaklad o ktery je mozno se oprit pri hledani problemu
s alokaci i v dobe "opravdovych" objektu.

Ovsem co si budeme povidat, takova garbage collection
je pro programatora pozehnani...

Martin Schayna